/*	--- 使用reduce ---


map() 和 filter() 都是【Stream的转换方法】，而 Stream.reduce() 则是 【Stream的一个聚合方法】，它可以把【一个Stream的所有元素】按照【聚合函数】聚合成【一个结果】。

我们来看一个【简单的聚合方法】：*/
import java.util.stream.*;

public class Main {
	public static void main(String[] args) {
		int sum = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9)
						.reduce(0, (acc, n) -> acc + n);

		System.out.println(sum); // 45
	}
}


/*
reduce()方法传入的对象是【BinaryOperator接口】，它定义了一个【apply()方法】，负责把【上次累加的结果】和【本次的元素 进行 运算】，并返回【累加的结果】：*/
@FunctionalInterface
public interface BinaryOperator<T> {
	// Binary操作: 2个输入，1个输出
	T apply(T t, T u);
}


/*
上述代码看上去不好理解，

但我们用for循环改写一下，就容易理解了：*/
Stream<Integer> stream = ...;
int sum = 0;

for (n : stream) {
	sum = (sum, n) -> sum + n;
}


/*
可见，【reduce()操作】首先初始化【结果】为【指定值（这里是0）】，

紧接着，【reduce()】对【每个元素】依次调用【(acc, n) -> acc + n】，

其中，acc是上次计算的结果：

	// 计算过程:
	acc = 0 // 初始化为指定值
	acc = acc + n = 0 + 1 = 1 // n = 1
	acc = acc + n = 1 + 2 = 3 // n = 2
	acc = acc + n = 3 + 3 = 6 // n = 3
	acc = acc + n = 6 + 4 = 10 // n = 4
	acc = acc + n = 10 + 5 = 15 // n = 5
	acc = acc + n = 15 + 6 = 21 // n = 6
	acc = acc + n = 21 + 7 = 28 // n = 7
	acc = acc + n = 28 + 8 = 36 // n = 8
	acc = acc + n = 36 + 9 = 45 // n = 9


因此，实际上这个 reduce()操作 是一个 求和。

如果去掉【初始值】，我们会得到一个 Optional<Integer>：*/
Optional<Integer> opt = stream.reduce((acc, n) -> acc + n);

if (opt.isPresent) {
	System.out.println(opt.get());
}


/*
这是因为 Stream的元素 有可能是 0个，这样就没法调用 reduce()的聚合函数了，因此返回【Optional对象】，需要进一步判断【结果】是否存在。

利用 reduce()，我们可以把【求和】改成【求积】，代码也十分简单：*/
import java.util.stream.*;

public class Main {
	public static void main(String[] args) {
		int s = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9).reduce(1, (acc, n) -> acc * n);
		System.out.println(s); // 362880
	}
}


/*
注意：计算求积时，初始值必须设置为1。

除了可以对数值进行累积计算外，灵活运用reduce()也可以对Java对象进行操作。

下面的代码演示了如何将配置文件的每一行配置通过map()和reduce()操作聚合成一个Map<String, String>：*/
import java.util.*;

public class Main {
	public static void main(String[] args) {
		// 按行读取配置文件：
		List<String> props = List.of("profile = native", "debug = true", "logging = warn", "interval = 500");

		Map<String, String> map = props.stream()
									   .map(kv -> {
									   		String[] ss = kv.split("\\=", 2);
									   		return Map.of(ss[0], ss[1]);
									   })

									   // 把所有Map聚合到一个Map:
									   .reduce(new HashMap<String, String>(), (m, kv) -> {
									   		m.putAll(kv);
									   		return m;
									   });
    	
    	// 打印结果:
		map.forEach((k, v) -> {
			System.out.println(k + " = " + v);
		});
	}
}



/*==========================================================


#	----- 使用reduce の 小结 ----- 


1. 【reduce()方法】将【一个Stream的每个元素】依次作用于【BinaryOperator】，并将【结果】合并。

2. 【reduce()】是【聚合方法】，【聚合方法】会立刻对【Stream】进行计算。


*/




















